package com.jindouyun.consumer.client;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jindouyun.common.entity.JDYRequest;
import com.jindouyun.common.entity.JDYResponse;
import com.jindouyun.common.exception.JdyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;


/**
 * @className: com.jindouyun.consumer.client.ClientProxy
 * @description: 客戶端代理类实现
 * @author: tong.li
 * @createTime: 2021/10/14 15:31
 * @copyright: Tongcheng-Elong Holdings Limited
 */
@Component
public class ClientProxy {

    private final Logger log = LoggerFactory.getLogger(ClientProxy.class);

    /**
     * 缓存代理的对象，对同一个接口代理只生成一次代理对象
     */
    public static final Map<Class, Object> PROXY_INSTANCE_CACHE =  new ConcurrentHashMap<>();


    @Resource
    private RpcClient client;

    @Resource
    private ObjectMapper objectMapper;



    /**
     * 客户端代理请求
     * @param serviceClass
     * @return
     */
    public Object proxyExecute(Class serviceClass) {
        Object proxy = PROXY_INSTANCE_CACHE.get(serviceClass);
        if (proxy != null) {
            // 如果已经生成代理对象，直接返回即可
            return proxy;
        }
        // 通过JDK基于接口生成代理类
        proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{serviceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws ExecutionException, InterruptedException, JsonProcessingException {
                // 封装请对象
                JDYRequest request = new JDYRequest();
                request.setRequestId(UUID.randomUUID().toString().replace("-",""));
                request.setServiceName(method.getDeclaringClass().getName());
                request.setActionName(method.getName());
                request.setParameterTypes(method.getParameterTypes());
                request.setParameters(args);
                JDYResponse response = null;
                try {
                    // 發送消息
                    String s = objectMapper.writeValueAsString(request);
                    Object resp = client.send(s);
                    response = objectMapper.readValue(resp.toString(), JDYResponse.class);
                    if (response == null || response.getCode() != JDYResponse.ResponseCodeEnums.OK.getCode()) {
                        throw new JdyException(response == null ? "服务端未响应":response.getMessage());
                    }
                    Object data = response.getData();
                    if (data != null) {
                        return objectMapper.readValue(objectMapper.writeValueAsString(response.getData()),method.getReturnType());
                    }
                    return response;
                } catch (Exception e) {
                    log.error("客户端发送异常",e);
                    throw e;
                }
            }
        });
        PROXY_INSTANCE_CACHE.put(serviceClass, proxy);
        return proxy;
    }


}
